package com.dyna.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.dyna.constants.ModuleErrorCodeConstants;
import com.dyna.core.exception.CustomException;
import com.dyna.core.utils.MapUtil;
import com.dyna.core.utils.ObjectUtil;
import com.dyna.domain.resp.PageResult;
import com.dyna.enums.CommonStatusEnum;
import com.dyna.foundation.domain.entity.SysDictData;
import com.dyna.foundation.domain.entity.SysDictType;
import com.dyna.foundation.domain.req.SysDictDataPageReq;
import com.dyna.foundation.domain.resp.SysDictDataResp;
import com.dyna.foundation.domain.resp.SysDictDataSaveForm;
import com.dyna.foundation.domain.resp.SysDictDataSimpleResp;
import com.dyna.mapper.SysDictDataMapper;
import com.dyna.service.SysDictDataService;
import com.dyna.service.SysDictTypeService;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 字典数据 Service 实现类
 *
 * @author ruoyi
 */
@Service
@Slf4j
public class SysDictDataServiceImpl implements SysDictDataService {

    /**
     * 排序 dictType > sort
     */
    private static final Comparator<SysDictData> COMPARATOR_TYPE_AND_SORT = Comparator
            .comparing(SysDictData::getDictType)
            .thenComparingInt(SysDictData::getDictSort);

    @Resource
    @Lazy
    private SysDictTypeService dictTypeService;

    @Resource
    private SysDictDataMapper dictDataMapper;

    @Override
    public List<SysDictDataSimpleResp> getDictDataList(Integer status, String dictType) {
        List<SysDictData> list = dictDataMapper.selectListByStatusAndDictType(status, dictType);
        list.sort(COMPARATOR_TYPE_AND_SORT);
        List<SysDictDataSimpleResp> result = list.stream().map(it -> {
            SysDictDataSimpleResp simpleResp = new SysDictDataSimpleResp();
            simpleResp.setDictType(it.getDictType());
            simpleResp.setValue(it.getDictValue());
            simpleResp.setLabel(it.getDictLabel());
            simpleResp.setColorType(it.getColorType());
            simpleResp.setCssClass(it.getCssClass());
            return simpleResp;
        }).collect(Collectors.toList());
        return result;
    }

    @Override
    public PageResult<SysDictDataResp> getDictDataPage(SysDictDataPageReq pageReqVO) {
        PageResult<SysDictData> pageResult = dictDataMapper.selectPage(pageReqVO);
        List<SysDictDataResp> list = pageResult.getList().stream().map(it -> {
            SysDictDataResp resp = new SysDictDataResp();
            resp.setId(it.getDictId());
            resp.setSort(it.getDictSort());
            resp.setLabel(it.getDictLabel());
            resp.setValue(it.getDictValue());
            resp.setDictType(it.getDictType());
            resp.setStatus(it.getStatus());
            resp.setColorType(it.getColorType());
            resp.setCssClass(it.getCssClass());
            resp.setCreateTime(it.getCreateTime());
            return resp;
        }).collect(Collectors.toList());
        return new PageResult<>(list, pageResult.getTotal());
    }

    @Override
    public SysDictData getDictData(Long id) {
        return dictDataMapper.selectById(id);
    }

    @Override
    public Integer createDictData(SysDictDataSaveForm createReqVO) {
        // 校验字典类型有效
        validateDictTypeExists(createReqVO.getDictType());
        // 校验字典数据的值的唯一性
        validateDictDataValueUnique(null, createReqVO.getDictType(), createReqVO.getValue());

        // 插入字典类型
        SysDictData dictData = BeanUtil.toBean(createReqVO, SysDictData.class);
        dictDataMapper.insert(dictData);
        return dictData.getDictId();
    }

    @Override
    public void updateDictData(SysDictDataSaveForm updateReqVO) {
        // 校验自己存在
        validateDictDataExists(updateReqVO.getId());
        // 校验字典类型有效
        validateDictTypeExists(updateReqVO.getDictType());
        // 校验字典数据的值的唯一性
        validateDictDataValueUnique(updateReqVO.getId(), updateReqVO.getDictType(), updateReqVO.getValue());

        // 更新字典类型
        SysDictData updateObj = BeanUtil.toBean(updateReqVO, SysDictData.class);
        dictDataMapper.updateById(updateObj);
    }

    @Override
    public void deleteDictData(Long id) {
        // 校验是否存在
        validateDictDataExists(id);

        // 删除字典数据
        dictDataMapper.deleteById(id);
    }

    @Override
    public long getDictDataCountByDictType(String dictType) {
        return dictDataMapper.selectCountByDictType(dictType);
    }

    @VisibleForTesting
    public void validateDictDataValueUnique(Long id, String dictType, String value) {
        SysDictData dictData = dictDataMapper.selectByDictTypeAndValue(dictType, value);
        if (dictData == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的字典数据
        if (ObjectUtil.isNull(id) || !dictData.getDictId().equals(id)) {
            throw new CustomException(ModuleErrorCodeConstants.DICT_DATA_VALUE_DUPLICATE.getMsg());
        }
    }

    @VisibleForTesting
    public void validateDictDataExists(Long id) {
        if (id == null) {
            return;
        }
        SysDictData dictData = dictDataMapper.selectById(id);
        if (dictData == null) {
            throw new CustomException(ModuleErrorCodeConstants.DICT_DATA_NOT_EXISTS.getMsg());
        }
    }

    @VisibleForTesting
    public void validateDictTypeExists(String type) {
        SysDictType dictType = dictTypeService.getDictType(type);
        if (ObjectUtil.isNull(dictType)) {
            throw new CustomException(ModuleErrorCodeConstants.DICT_TYPE_NOT_EXISTS.getMsg());
        }
        if (!CommonStatusEnum.ENABLE.getStatus().equals(dictType.getStatus())) {
            throw new CustomException(ModuleErrorCodeConstants.DICT_TYPE_NOT_ENABLE.getMsg());
        }
    }

    @Override
    public void validateDictDataList(String dictType, Collection<String> values) {
        if (CollUtil.isEmpty(values)) {
            return;
        }
        Map<String, SysDictData> dictDataMap = MapUtil.convertMap(
                dictDataMapper.selectByDictTypeAndValues(dictType, values), SysDictData::getDictValue);
        // 校验
        values.forEach(value -> {
            SysDictData dictData = dictDataMap.get(value);
            if (dictData == null) {
                throw new CustomException(ModuleErrorCodeConstants.DICT_DATA_NOT_EXISTS.getMsg());
            }
            if (!CommonStatusEnum.ENABLE.getStatus().equals(dictData.getStatus())) {
                throw new CustomException(StrUtil.format(ModuleErrorCodeConstants.DICT_DATA_NOT_ENABLE.getMsg(), dictData.getDictLabel()));
            }
        });
    }

    @Override
    public SysDictData getDictData(String dictType, String value) {
        return dictDataMapper.selectByDictTypeAndValue(dictType, value);
    }

    @Override
    public SysDictData parseDictData(String dictType, String label) {
        return dictDataMapper.selectByDictTypeAndLabel(dictType, label);
    }

    @Override
    public List<SysDictData> getDictDataListByDictType(String dictType) {
        List<SysDictData> list = dictDataMapper.selectList(SysDictData::getDictType, dictType);
        list.sort(Comparator.comparing(SysDictData::getDictSort));
        return list;
    }

}
